from PyQt4.QtSql import QSqlDatabase, QSqlQuery, QSqlTableModel
from PyQt4.QtCore import Qt, QVariant, QAbstractItemModel, QModelIndex, SIGNAL, QObject
import weakref


def setUpModels():
    DBNAME = 'lists.db'

    db = QSqlDatabase.addDatabase('QSQLITE')
    db.setDatabaseName(DBNAME)
    db.open()

    taskModel = TaskModel()
    listModel = QSqlTableModel()
    listModel.setTable('list')
    listModel.select()
    listModel.removeColumn(0)

    return listModel, taskModel

 
class Parent(object): # maybe this is too much.
    def __init__(self):
        self.childs = []

    def addChild(self, child):
        i = len(self.childs)
        child.row = i
        self.childs.append(child)

    def getChildN(self, n):
        ret = None
        if n < len(self.childs) and n >= 0:
            ret = self.childs[n]

        return ret


class RootTask(Parent):
    pass


class Task(Parent):
    taskIds = {}
    root = RootTask() # so we can test using 'aTask is root'

    def __init__(self, id, descr, done, parent):
        super(Task, self).__init__()
        self.id     = id
        self.descr  = descr
        self.done   = done 
        self.parent = parent #weakref.ref(parent)

        parent.addChild(self)
        Task.taskIds[id] = self

    def getParent(self):
        return self.parent

    @classmethod
    def populate(cls, data):
        cls.root    = RootTask()
        cls.taskIds = {0: cls.root}

        while data.next():
            row = data.record()
            t = cls.fromRow(row)

    @classmethod 
    def getTask(cls, id):
        return cls.taskIds[id]

    @classmethod
    def fromRow(cls, row):
        id       = row.value('id').toInt()[0]
        descr    = row.value('descr').toString()
        checked  = row.value('done').toBool()
        parentId = row.value('parent').toInt()[0]
        parent   = cls.getTask(parentId) 

        return Task(id, descr, checked, parent)


class TaskModel(QAbstractItemModel):
    def __init__(self):
        super(TaskModel, self).__init__()
        self.tasksQuery = QSqlQuery('''
            SELECT *
            FROM task INNER JOIN list 
                ON task.list = list.id 
            WHERE list.name = :currList''')

        self.updateQuery = QSqlQuery('''
            UPDATE task
            SET descr = :descr, done = :done
            WHERE task.id = :id''')
        self.setFirstList()

    def setList(self, name):
        self.tasksQuery.bindValue(':currList', QVariant(name))
        self.tasksQuery.exec_()
        Task.populate(self.tasksQuery)
        self.tasksQuery.finish()

    def updateTask(self, task):
        self.updateQuery.bindValue(':descr', QVariant(task.descr))
        self.updateQuery.bindValue(':done', QVariant(int(task.done)))
        self.updateQuery.bindValue(':id', QVariant(task.id))
        self.updateQuery.exec_()
        self.updateQuery.finish()

    def setFirstList(self):
        #TO-DO save current list and use that. ie, change to setLastList
        q = QSqlQuery('SELECT name FROM list')
        q.exec_()
        q.next()
        self.setList(q.value(0).toString())
        q.finish()
        
    def index(self, row, col, parent = QModelIndex()):
        if not parent.isValid():
            parent = Task.root
        else:
            parent = parent.internalPointer()

        task = parent.getChildN(row)
        if task is None:
            return QModelIndex()
        return self.createIndex(row, col, task)
        
    def parent(self, child):
        if child.isValid():
            childTask = child.internalPointer()
            parent = childTask.getParent()
            if not parent is Task.root:
                return self.createIndex(parent.row, 0, parent)

        return QModelIndex()

    def rowCount(self, parent):
        if parent.isValid():
            parent = parent.internalPointer()
        else:
            parent = Task.root

        return len(parent.childs)

    def columnCount(self, parent):
        return 1

    def getDescr(self, index):
        return QVariant(index.internalPointer().descr)

    def getChecked(self, index):
        ret = Qt.Unchecked
        if index.internalPointer().done:
            ret = Qt.Checked

        return QVariant(ret)

    def data(self, index, role):
        if role == Qt.CheckStateRole:
            return self.getChecked(index)
        elif role == Qt.DisplayRole:
            return self.getDescr(index)

        return QVariant()

    def setData(self, index, value, role = Qt.EditRole):
        if index.isValid():
            task = index.internalPointer()
            
            if role == Qt.EditRole:
                task.descr = value.toString()
            elif role == Qt.CheckStateRole:
                task.done = not not value.toInt()[0] # not not converts to bool

            self.updateTask(task)
            return True

        return False

    def flags(self, index):
        ret = QAbstractItemModel.flags(self, index)
        return ret | Qt.ItemIsEditable | Qt.ItemIsUserCheckable

